<!-- 表单 》 滑块范围 -->

<template>
  <el-form-item v-bind="formItem">
    <!-- 标签 -->
    <template v-if="hasLabelSlot" #label>
      <slot name="label" :label="formItem.label">{{ formItem.label }}</slot>
    </template>

    <el-slider v-model="model" v-bind="sliderProps" range @change="emitChange" />
  </el-form-item>
</template>

<script>
// ============================== 导入依赖 ============================== //

import CORE from '@/CORE'
import mixForm from '../mixForm'
import FormSlider from '../FormSlider'

const name = 'FormSliderRange'

// ============================== 导出组件 ============================== //

export default {
  /**
   * 名称定义 (实际使用名称)
   */
  name,

  /**
   * 混入列表 (配置选项合并)
   */
  mixins: [mixForm],

  /**
   * 属性注册 (抽取以便查阅)
   */
  props: CORE.WEB[name],

  /**
   * 状态数据 (函数返回对象)
   */
  data() {
    const { min } = this
    return {
      model: [min, min], // 内部绑定值
    }
  },

  /**
   * 计算属性 (慎用箭头函数)
   */
  computed: {
    ...FormSlider.computed,

    /**
     * 初始的开始值
     */
    initBegin() {
      const { init, validNum, min } = this
      return CORE.isArray(init) && validNum(init[0]) ? init[0] : min
    },

    /**
     * 初始的结束值
     */
    initEnd() {
      const { init, validNum, max } = this
      return CORE.isArray(init) && validNum(init[1]) ? init[1] : max
    },
  },

  /**
   * 监听属性 (深度 deep 首次 immediate)
   */
  watch: FormSlider.watch,

  /**
   * 本地方法 (轻量重要在前)
   */
  methods: {
    /**
     * 是否不等 (可覆盖)
     */
    isDiff() {
      const { obj, prop, bindList, isMulti, model, EMPTY, string, validNum } = this

      const values = isMulti
        ? [obj[bindList[0]], obj[bindList[1]]]
        : CORE.isArray(obj[prop]) ? [obj[prop][0], obj[prop][1]] : [EMPTY, EMPTY]

      const begin = string ? Number(values[0] || '') : values[0]
      const end = string ? Number(values[1] || '') : values[1]

      // 判断两数是否在有效范围内
      if (!validNum(begin) || !this.validNum(end)) return true

      return begin !== model[0] || end !== model[1]
    },

    /**
     * 设置内部绑定值 (可覆盖)
     */
    setModel() {
      const { obj, prop, bindList, isMulti, initBegin, initEnd, string, validNum, transValues } = this
      const values = isMulti ? [obj[bindList[0]], obj[bindList[1]]] : obj[prop]

      let begin, end
      if (!CORE.isArray(values)) {
        begin = initBegin
        end = initEnd
      } else if (string) {
        begin = validNum(+values[0]) ? +values[0] : initBegin
        end = validNum(+values[1]) ? +values[1] : initEnd
      } else {
        begin = validNum(values[0]) ? values[0] : initBegin
        end = validNum(values[1]) ? values[1] : initEnd
      }

      this.model = transValues([begin, end])
    },

    /**
     * 获取最终回传值 (可覆盖)
     */
    getValue() {
      const { model, string, transValues, emitChange } = this
      const [begin, end] = transValues(model)

      if (model[0] !== begin || model[1] !== end) {
        this.model = [begin, end] // 更新绑定值
        setTimeout(() => emitChange()) // 重新走提交流程
      }

      return string ? [`${begin}`, `${end}`] : model
    },

    /**
     * 是否相等 (可覆盖)
     */
    equals(values) {
      const { obj, prop, bindList, isMulti, EMPTY } = this

      const [begin, end] = isMulti
        ? [obj[bindList[0]], obj[bindList[1]]]
        : CORE.isArray(obj[prop]) ? [obj[prop][0], obj[prop][1]] : [EMPTY, EMPTY]

      return begin === values[0] && end === values[1]
    },

    /**
     * 提交改变
     */
    emitChange() {
      const { obj, prop, bindList, isMulti } = this

      // 获取新值
      const values = this.getValue()

      // 判断改变
      if (this.onlyShow || this.equals(values)) return

      // 判断是否绑定的两个属性
      if (isMulti) {
        if (obj[bindList[0]] === values[0] && obj[bindList[1]] === values[1]) return

        this.$set(obj, bindList[0], values[0])
        this.$set(obj, bindList[1], values[1])
        this.$emit('change', values)
      } else {
        if (JSON.stringify(obj[prop]) === JSON.stringify(values)) return

        this.$set(obj, prop, values)
        this.$emit('change', values)
      }

      // 提交之后
      this.afterEmit()
    },

    /**
     * 转换数值对
     */
    transValues(values) {
      const { min, max, minGap, minLeft, maxGap, maxLeft } = this
      let [begin, end] = values

      // 判断两数大小
      if (begin > end) [begin, end] = [end, begin]

      // 判断最小差值
      if (minGap && end - begin < minGap) {
        if (minLeft) { // 优先向左扩展
          if (end - minGap >= min) end = end - minGap
          else if (begin + minGap <= max) end = begin + minGap
          else {
            end = max
            begin = max - minGap >= min ? max - minGap : min
          }
        } else { // 优先向右扩展
          if (begin + minGap <= max) end = begin + minGap
          else if (end - minGap >= min) end = end - minGap
          else {
            begin = min
            end = min + minGap <= max ? min + minGap : max
          }
        }
      }

      // 最大差值
      if (maxGap && end - begin > maxGap) {
        if (maxLeft) { // 优先向左压缩
          begin = end - maxGap
        } else { // 优先向右压缩
          end = begin + maxGap
        }
      }

      return [begin, end]
    },

    /**
     * 重新设置内部绑定值
     */
    resetModel: FormSlider.methods.resetModel,

    /**
     * 是否为有效数字
     */
    validNum: FormSlider.methods.validNum,
  },
}
</script>
